package cn.xd.base.persistence.repository.impl;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.xd.base.basic.enums.DictKeyTypeEnum;
import cn.xd.base.basic.type.*;
import cn.xd.base.domain.entity.Dict;
import cn.xd.base.domain.entity.KeyValue;
import cn.xd.base.domain.repository.KeyValueRepository;
import cn.xd.base.persistence.dos.DictConverter;
import cn.xd.base.persistence.dos.DictDO;
import cn.xd.base.persistence.dos.KeyValueConverter;
import cn.xd.base.persistence.dos.KeyValueDO;
import cn.xd.base.persistence.mapper.KeyValueVOMapper;
import cn.xd.base.persistence.mps.DictMpService;
import cn.xd.base.persistence.mps.KeyValueMpService;
import cn.xd.core.ddd.db.DbRepositorySupport;
import cn.xd.core.ddd.diff.Diff;
import cn.xd.core.ddd.diff.EntityDiff;
import cn.xd.core.response.CollectResult;
import cn.xd.core.response.ObjectResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @author : mirzaLin
 * @data : 2023/11/20
 * @description :
 **/
@Repository
public class KeyValueRepositoryImpl extends DbRepositorySupport<KeyValue, KeyValueId> implements KeyValueRepository {

    @Resource
    private KeyValueMpService keyValueMpService;
    @Resource
    private DictMpService dictMpService;
    @Resource
    private KeyValueVOMapper keyValueVOMapper;


    @Override
    protected void onInsert(KeyValue aggregate) {
        DictDO dictDO = dictMpService.getOneForLimitOneResult(
                Wrappers.lambdaQuery(DictDO.class).eq(DictDO::getCode, aggregate.getDictCode().getValue())

        ).isEmptyThrow("未知的字典：" + aggregate.getDictCode().getValue());
        Dict dict = DictConverter.INSTANCE.fromData(dictDO);
        if (!dictDO.getAutoDictKey()) {
            dict.check(aggregate.getDictKey().getValue());
            // 验证，同一类型(type)中的名称（key）不能重复
            find(aggregate.getDictCode(), aggregate.getDictKey()).isNotEmptyThrow("该类型Key值已存在");
        }
        Integer parentLevel = 0;
        String path = dictDO.getDictKeyType().equals(DictKeyTypeEnum.STRING.getCode())
                ? aggregate.getId().getValue().toString() : aggregate.getDictKey().getValue();
        if (aggregate.getParentId().getValue() != 0) {
            KeyValue parent = find(aggregate.getParentId()).isEmptyThrow("该父节点不存在");
            parentLevel = parent.getLevel().getValue();
            if (!dictDO.getAutoDictKey()) {
                path = parent.getPath().getValue() + path + "/";
            } else {
                path = parent.getPath().getValue();
            }
        } else if (!dictDO.getAutoDictKey()) {
            path = path + "/";
        }
        aggregate.setLevel(TreeLevel.ofParentLevel(parentLevel));
        aggregate.setPath(TreePath.of(path));
        // 验证，同一类型(type)中的值（value）不能重复
        find(aggregate.getDictCode(), aggregate.getParentId(), aggregate.getDictValue()).isNotEmptyThrow("该类型Value值已存在");
        if (dictDO.getAutoDictKey()) {
            keyValueVOMapper.saveByAutoKey(KeyValueConverter.INSTANCE.toData(aggregate));
            aggregate.setDictKey(KeyValueKey.of(keyValueVOMapper.selectMaxDictKey(aggregate.getDictCode().getValue())));
        } else {
            keyValueMpService.saveResult(aggregate, KeyValueConverter.INSTANCE);
        }
    }

    @Override
    protected KeyValue onSelect(KeyValueId id) {
        return keyValueMpService.getResult(id, KeyValueConverter.INSTANCE).get();
    }

    @Override
    protected void onUpdate(KeyValue aggregate, EntityDiff diff) {
        if (diff.isSelfModified()) {
            KeyValueDO bean = diff.getBean(KeyValueDO.class);
            DictDO dictDO = dictMpService.getOneForLimitOneResult(Wrappers.lambdaQuery(DictDO.class).eq(DictDO::getCode, aggregate.getDictCode().getValue())).isEmptyThrow("未知的字典：" + aggregate.getDictCode().getValue());

            //自动生成key不能修改key
            if (dictDO.getAutoDictKey() && StrUtil.isNotBlank(bean.getDictKey())) {
                Diff dictKeyDiff = (Diff) diff.getDiff("dictKey");
                String oldDictKey = (String) dictKeyDiff.getOldValue();
                dictKeyDiff.setNewValue(oldDictKey);
                bean.setDictKey(null);
            }
            Dict dict = DictConverter.INSTANCE.fromData(dictDO);
            dict.check(aggregate.getDictKey().getValue());

            if (StrUtil.isNotBlank(bean.getDictKey())) {
                // 验证，同一类型(type)中的名称（key）不能重复
                find(aggregate.getDictCode(), aggregate.getDictKey()).isNotEmptyThrow("该类型Key值已存在");
            }
            if (StrUtil.isNotBlank(bean.getDictValue())) {
                find(aggregate.getDictCode(), aggregate.getParentId(), KeyValueValue.of(bean.getDictValue())).isEmptyThrow("该类型Value值已存在");
            }
            if (ObjUtil.isNotNull(bean.getParentId())) {
                int level = 0;
                String path = dictDO.getDictKeyType().equals(DictKeyTypeEnum.STRING.getCode())
                        ? aggregate.getId().getValue().toString() : aggregate.getDictKey().getValue();
                if (aggregate.getParentId().getValue() != 0) {
                    KeyValue parent = find(aggregate.getParentId()).isEmptyThrow("该父节点不存在");
                    level = parent.getLevel().getValue() + 1;
                    path = parent.getPath().getValue() + path + "/";
                } else {
                    path = path + "/";
                }
                bean.setLevel(level);
                bean.setPath(path);
            }
            keyValueMpService.updateResult(bean);
        }
    }

    @Override
    protected void onDelete(KeyValue aggregate) {
        keyValueMpService.remove(Wrappers.lambdaQuery(KeyValueDO.class)
                .eq(KeyValueDO::getDictCode, aggregate.getDictCode().getValue())
                .like(KeyValueDO::getPath, aggregate.getPath().getValue())
        );
    }

    /**
     * 通过类型查找<b><i>其中一条</i></b>符合的记录
     *
     * @param type 类型
     * @return 字典配置
     */
    @Override
    public ObjectResult<KeyValue> findOneForLimitOne(DictCode type) {
        LambdaQueryWrapper<KeyValueDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(type.getValue()), KeyValueDO::getDictCode, type.getValue());
        KeyValueDO keyValueDO = keyValueMpService.getOneForLimitOneResult(wrapper).get();
        if (ObjUtil.isNull(keyValueDO)) {
            return ObjectResult.of(null);
        }
        KeyValue keyValue = KeyValueConverter.INSTANCE.fromData(keyValueDO);
        return ObjectResult.of(keyValue);
    }

    /**
     * 通过类型、名称查找一条记录
     *
     * @param type     类型
     * @param parentId 父类id
     * @param value    值
     * @return 字典配置
     */
    @Override
    public ObjectResult<KeyValue> find(DictCode type, KeyValueId parentId, KeyValueValue value) {
        LambdaQueryWrapper<KeyValueDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(type.getValue()), KeyValueDO::getDictCode, type.getValue());
        wrapper.eq(ObjUtil.isNotNull(parentId.getValue()), KeyValueDO::getParentId, parentId.getValue());
        wrapper.eq(StrUtil.isNotBlank(value.getValue()), KeyValueDO::getDictValue, value.getValue());
        KeyValueDO keyValueDO = keyValueMpService.getOneForLimitOneResult(wrapper).get();
        if (ObjUtil.isNull(keyValueDO)) {
            return ObjectResult.of(null);
        }
        KeyValue keyValue = KeyValueConverter.INSTANCE.fromData(keyValueDO);
        return ObjectResult.of(keyValue);
    }

    /**
     * 通过类型和值查找一条记录
     *
     * @param type 类型
     * @param key  内容/值
     * @return 字典配置
     */
    @Override
    public ObjectResult<KeyValue> find(DictCode type, KeyValueKey key) {
        LambdaQueryWrapper<KeyValueDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(type.getValue()), KeyValueDO::getDictCode, type.getValue());
        wrapper.eq(ObjUtil.isNotNull(key.getValue()), KeyValueDO::getDictKey, key.getValue());
        KeyValue keyValue = keyValueMpService.getOneForLimitOneResult(wrapper, KeyValueConverter.INSTANCE).isNotEmpty(this::attach);
        return ObjectResult.of(keyValue);
    }


    @Override
    public CollectResult<KeyValue> getKeyValuesByParentId(Boolean filterWithoutShow, DictCode type, KeyValueId id) {
        List<KeyValueDO> list = keyValueMpService.lambdaQuery().eq(KeyValueDO::getParentId, id.getValue())
                .eq(filterWithoutShow, KeyValueDO::getDisplay, Boolean.TRUE)
                .eq(KeyValueDO::getDictCode, type.getValue()).orderByDesc(KeyValueDO::getId).list();
        List<KeyValue> keyValues = KeyValueConverter.INSTANCE.fromData(list);
        return CollectResult.of(keyValues);
    }

    @Override
    public CollectResult<KeyValue> getKeyValueByType(DictCode type) {
        List<KeyValueDO> list = keyValueMpService.lambdaQuery().eq(KeyValueDO::getDictCode, type.getValue()).list();
        List<KeyValue> keyValues = KeyValueConverter.INSTANCE.fromData(list);
        for (KeyValue keyValue : keyValues) {
            this.attach(keyValue);
        }
        return CollectResult.of(keyValues);
    }
}
